﻿using System;
using System.Text;
using System.Linq;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;

namespace Admin.CYT369.Com.DAL.Services
{
    /// <summary>
    /// 系统用户服务
    /// </summary>
    public class UserService : Admin.CYT369.Com.DAL.DbContexts.BaseService<UserService>
    {
        public UserService() { }

        public bool IsAdministrators(Microsoft.EntityFrameworkCore.DbContext db, int userId)
        {
            if (userId > 0)
            {
                if (db == null)
                {
                    db = this.Ctx;
                }

                var adminRoles = from o in db.Set<Admin.CYT369.Com.DAL.Domains.sys.UserRole>()
                                 where o.UserId == userId
                                 join ff in db.Set<Admin.CYT369.Com.DAL.Domains.Role>() on o.RoleId equals ff.Id
                                 where ff.IsInternal == true && ff.Name == Admin.CYT369.Com.Utility.ConstStringClass.Administrators
                                 select o;

                return adminRoles.Count() > 0;
            }

            return false;
        }

        /// <summary>
        /// 变更用户头像
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="avatar"></param>
        /// <returns></returns>
        public bool ChangeUserAvatar(int userId, string avatar) {
            using (var db = this.Ctx) {
                var user = db.Set<Admin.CYT369.Com.DAL.Domains.SysUser>().Where(c => c.Id == userId).FirstOrDefault();
                if (user != null) {
                    user.Avatar = avatar;

                    db.SaveChanges();
                    return true;
                }

            }

            return false;
        }

        public bool ChangeUserPassword(Admin.CYT369.Com.DAL.Domains.SysUser user)
        {
            using (var db = this.Ctx)
            {
                var item = db.Set<Admin.CYT369.Com.DAL.Domains.SysUser>().Where(c => c.Id == user.Id).FirstOrDefault();
                if (item != null)
                {
                    item.PasswordHash = user.PasswordHash;

                    db.SaveChanges();
                    return true;
                }
            }

            return false;
        }

        #region Users
        public IQueryable<Admin.CYT369.Com.DAL.Domains.SysUser> GetUsers(int page, int rows, ref int total,
                                                         int? organizationId = null, int? departmentId = null,
                                                         int? roleId = null, int? notInRoleId = null,
                                                         string fullName = null, string userName = null)
        {
            var db = this.Ctx;
            var items = from o in db.Set<Admin.CYT369.Com.DAL.Domains.SysUser>()
                        where o.Deleted == false
                        select o;

            #region 机构与部门查询
            IEnumerable<int> departmentUserIds = null;
            if (organizationId.HasValue)
            {
                var departments = from o in db.Set<Admin.CYT369.Com.DAL.Domains.Department>()
                                  where o.OrgID == organizationId.Value
                                  select o;

                var departmentUsers = from o in db.Set<Admin.CYT369.Com.DAL.Domains.DepartmentUser>()
                                      join j in departments on o.DepartmentID equals j.Id
                                      select o;

                if (departmentId.HasValue)
                {
                    departmentUsers = departmentUsers.Where(c => c.DepartmentID == departmentId.Value);
                }

                departmentUserIds = (from o in departmentUsers
                                     select o.UserID).ToArray().Distinct();
            }
            else if (departmentId.HasValue)
            {
                departmentUserIds = (from o in db.Set<Admin.CYT369.Com.DAL.Domains.DepartmentUser>()
                                     where o.DepartmentID == departmentId.Value
                                     select o.UserID).ToArray().Distinct();
            }

            if (departmentUserIds != null)
            {
                items = from o in items
                        where departmentUserIds.Contains(o.Id)
                        select o;
            }
            #endregion

            #region 角色查询
            if (roleId.HasValue)
            {
                var roleUsers = from o in db.Set<Admin.CYT369.Com.DAL.Domains.sys.UserRole>()
                                where o.RoleId == roleId.Value
                                select o;

                items = from o in items
                        join j in roleUsers on o.Id equals j.UserId
                        select o;
            }

            if (notInRoleId.HasValue)
            {
                var roleUsers = (from o in db.Set<Admin.CYT369.Com.DAL.Domains.sys.UserRole>()
                                 where o.RoleId == notInRoleId.Value
                                 select o.UserId).Distinct().ToList();

                items = from o in items
                        where !roleUsers.Contains(o.Id)
                        select o;
            }
            #endregion

            if (!string.IsNullOrEmpty(fullName))
            {
                items = items.Where(c => c.FullName.Contains(fullName));
            }

            if (!string.IsNullOrEmpty(userName))
            {
                items = items.Where(c => c.UserName.Contains(userName));
            }

            return this.Pagination(page, rows, ref total, items.Distinct(), c => c.Id);
        }


        public Admin.CYT369.Com.DAL.Domains.SysUser GetUserByID(int id)
        {
            return base.GetOne<Admin.CYT369.Com.DAL.Domains.SysUser>(c => c.Deleted == false && c.Id == id);
        }

        public Admin.CYT369.Com.DAL.Domains.SysUser FindUserByName(string userName)
        {
            return base.GetOne<Admin.CYT369.Com.DAL.Domains.SysUser>(c => c.Deleted == false && c.NormalizedUserName == userName);
        }

        /// <summary>
        /// 保存用户信息
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public bool SaveUser(Admin.CYT369.Com.DAL.Domains.SysUser user,List<Admin.CYT369.Com.DAL.Domains.DepartmentUser> departmentUsers, List<Admin.CYT369.Com.DAL.Domains.PositionUser> positionUsers)
        {
            using (var db = this.Ctx)
            {
                var item = (from o in db.Set<Admin.CYT369.Com.DAL.Domains.SysUser>()
                            where o.Id == user.Id
                            select o).FirstOrDefault();

                if (item == null)
                {
                    user.ChangedTime = DateTime.Now;
                    user.CreatedTime = DateTime.Now;
                    db.Set<Admin.CYT369.Com.DAL.Domains.SysUser>().Add(user);
                    db.SaveChanges();

                    foreach (var u in departmentUsers)
                    {
                        u.UserID = user.Id;
                    }
                    db.Set<Admin.CYT369.Com.DAL.Domains.DepartmentUser>().AddRange(departmentUsers);

                    foreach (var u in positionUsers)
                    {
                        u.UserID = user.Id;
                    }
                    db.Set<Admin.CYT369.Com.DAL.Domains.PositionUser>().AddRange(positionUsers);
                }
                else
                {
                    if (!item.IsInternal)
                    {
                        item.Code = user.Code;
                        item.UserName = user.UserName;
                        item.NormalizedUserName = user.NormalizedUserName;
                        item.FullName = user.FullName;
                        item.FullNameCode = user.FullNameCode;
                        item.Gender = user.Gender;
                        item.PhoneNumber = user.PhoneNumber;
                        item.Email = user.Email;
                        item.UserType = user.UserType;
                        item.Status = user.Status;
                        item.Enable = user.Enable;
                        item.Remark = user.Remark;
                        item.Address = user.Address;
                        item.ChangedTime = user.ChangedTime;

                        var dus = db.Set<Admin.CYT369.Com.DAL.Domains.DepartmentUser>().Where(c => c.UserID == item.Id);
                        db.Set<Admin.CYT369.Com.DAL.Domains.DepartmentUser>().RemoveRange(dus);
                        db.Set<Admin.CYT369.Com.DAL.Domains.DepartmentUser>().AddRange(departmentUsers);

                        var pus = db.Set<Admin.CYT369.Com.DAL.Domains.PositionUser>().Where(c => c.UserID == item.Id);
                        db.Set<Admin.CYT369.Com.DAL.Domains.PositionUser>().RemoveRange(pus);
                        db.Set<Admin.CYT369.Com.DAL.Domains.PositionUser>().AddRange(positionUsers);
                    }
                }
                db.SaveChanges();

                return true;
            }
        }

        public bool DeleteUser(int id)
        {
            return base.DoAction<Admin.CYT369.Com.DAL.Domains.SysUser>(c => c.Id == id, delegate (Admin.CYT369.Com.DAL.Domains.SysUser user)
            {
                var ticks = DateTime.Now.ToString("yyyyMMddHHmmss");
                user.UserName = string.Format("[删除{0}-{1}]", user.UserName, ticks);
                user.NormalizedUserName = string.Format("[删除{0}-{1}]", user.NormalizedUserName, ticks);
                user.Deleted = true;
                user.Enable = false;
            });
        }

        /// <summary>
        /// 重置密码
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="newPassword"></param>
        /// <returns></returns>
        public bool ResetUserPassword(Admin.CYT369.Com.DAL.Domains.SysUser user)
        {
            return base.DoAction<Admin.CYT369.Com.DAL.Domains.SysUser>(c => c.Id == user.Id && c.IsInternal == false, delegate (Admin.CYT369.Com.DAL.Domains.SysUser u)
            {
                u.PasswordHash = user.PasswordHash;
            });
        }
        #endregion

        #region Roles
        public IQueryable<Admin.CYT369.Com.DAL.Domains.Role> GetRoles(int page, int rows, ref int total, string name = null)
        {
            var items = base.Get<Admin.CYT369.Com.DAL.Domains.Role>();

            if (!string.IsNullOrEmpty(name))
            {
                items = items.Where(c => c.Name.Contains(name));
            }

            return this.Pagination(page, rows, ref total, items, c => c.Id);
        }

        public Admin.CYT369.Com.DAL.Domains.Role GetRoleByID(int id)
        {
            return base.GetOne<Admin.CYT369.Com.DAL.Domains.Role>(c => c.Id == id);
        }

        public bool DeleteRole(int id)
        {
            using (var db = this.Ctx)
            {
                var item = db.Set<Admin.CYT369.Com.DAL.Domains.Role>().Where(c => c.Id == id).FirstOrDefault();
                if (item != null)
                {
                    db.Set<Admin.CYT369.Com.DAL.Domains.Role>().Remove(item);
                    db.RemoveRange(db.Set<Admin.CYT369.Com.DAL.Domains.sys.UserRole>().Where(c => c.RoleId == id));

                    db.SaveChanges();
                }
            }

            return true;
        }

        public bool SaveRole(Admin.CYT369.Com.DAL.Domains.Role role)
        {
            using (var db = this.Ctx)
            {
                var item = (from o in db.Set<Admin.CYT369.Com.DAL.Domains.Role>()
                            where o.Id == role.Id
                            select o).FirstOrDefault();

                if (item == null)
                {
                    role.IsInternal = false;
                    role.ChangedTime = DateTime.Now;
                    role.CreatedTime = DateTime.Now;
                    db.Set<Admin.CYT369.Com.DAL.Domains.Role>().Add(role);
                }
                else
                {
                    if (!item.IsInternal)
                    {
                        item.Name = role.Name;
                        item.Description = role.Description;
                        item.Enable = role.Enable;
                        item.ChangedTime = DateTime.Now;
                    }
                }
                db.SaveChanges();

                return true;
            }
        }
        #endregion

        #region UserRoles
        public IQueryable<Admin.CYT369.Com.DAL.Domains.sys.UserRole> GetRoleUsersByRoleID(int page, int rows, ref int total, int roleId)
        {
            var items = base.Get<Admin.CYT369.Com.DAL.Domains.sys.UserRole>(c => c.RoleId == roleId);

            return this.Pagination(page, rows, ref total, items, c => c.Id);
        }

        public IQueryable<Admin.CYT369.Com.DAL.Domains.sys.UserRole> GetRoleUsersByUserID(int page, int rows, ref int total, int userId)
        {
            var items = base.Get<Admin.CYT369.Com.DAL.Domains.sys.UserRole>(c => c.UserId == userId);

            return this.Pagination(page, rows, ref total, items, c => c.Id);
        }

        /// <summary>
        /// 添加用户与角色的关系
        /// </summary>
        /// <param name="userRoles"></param>
        /// <returns></returns>
        public bool SaveRoleUser(IEnumerable<Admin.CYT369.Com.DAL.Domains.sys.UserRole> userRoles)
        {
            using (var db = this.Ctx)
            {
                foreach (var item in userRoles)
                {
                    if (db.Set<Admin.CYT369.Com.DAL.Domains.sys.UserRole>().Where(c => c.UserId == item.UserId && c.RoleId == item.RoleId).Count() <= 0)
                    {
                        db.Set<Admin.CYT369.Com.DAL.Domains.sys.UserRole>().Add(item);
                    }
                }

                db.SaveChanges();

                return true;
            }
        }

        /// <summary>
        /// 删除用户与角色的关系
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public bool DeleteRoleUser(int id)
        {
            return base.Delete<Admin.CYT369.Com.DAL.Domains.sys.UserRole>(c => c.Id == id);
        }

        /// <summary>
        /// 删除用户与角色的关系
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public bool DeleteRoleUserList(List<int> ids)
        {
            return base.Delete<Admin.CYT369.Com.DAL.Domains.sys.UserRole>(c => ids.Contains(c.Id));
        }
        #endregion

        #region RoleMenus
        public List<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenu> GetAppMenuTree()
        {
            var menus = base.Get<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenu>(c => c.Enable == true && c.Deleted == false).ToList();

            return _MakeAppMenuTree(menus, 0);
        }

        private List<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenu> _MakeAppMenuTree(IEnumerable<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenu> menus, int parentId)
        {
            var list = new List<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenu>();

            foreach (var menu in menus.Where(c => c.ParentID == parentId))
            {
                menu.SubMenus = _MakeAppMenuTree(menus, menu.Id);
                menu.state = menu.SubMenus.Count > 0 ? "closed" : "open";
                list.Add(menu);
            }

            return list;
        }

        /// <summary>
        /// 根据角色ID获取菜单功能列表
        /// </summary>
        /// <param name="roleId"></param>
        /// <returns></returns>
        public IQueryable<Admin.CYT369.Com.DAL.Domains.Apps.RoleMenu> GetRoleMenusByRoleID(int roleId)
        {
            return base.Get<Admin.CYT369.Com.DAL.Domains.Apps.RoleMenu>(c => c.RoleID == roleId);
        }

        /// <summary>
        /// 按菜单ID获取对应的权限操作列表
        /// </summary>
        /// <param name="menuId"></param>
        /// <returns></returns>
        public IQueryable<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenuOperation> GetAppMenuOperations(int menuId)
        {
            return base.Get<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenuOperation>(c => c.MenuID == menuId && c.Enable);
        }

        /// <summary>
        /// 获取角色-菜单-操作三者的关联关系
        /// </summary>
        /// <param name="roleId"></param>
        /// <param name="menuId"></param>
        /// <returns></returns>
        public IQueryable<Admin.CYT369.Com.DAL.Domains.Apps.RoleMenuOperation> GetRoleMenuOperations(int roleId, int menuId)
        {
            var db = this.Ctx;
            var roleMenu = db.Set<Admin.CYT369.Com.DAL.Domains.Apps.RoleMenu>().Where(c => c.RoleID == roleId && c.MenuID == menuId).FirstOrDefault();
            if (roleMenu != null)
            {
                return base.Get<Admin.CYT369.Com.DAL.Domains.Apps.RoleMenuOperation>(c => c.RoleMenuID == roleMenu.Id);
            }

            return null;
        }

        public Admin.CYT369.Com.DAL.Domains.Apps.AppOperation GetAppOperationByID(int id)
        {
            return base.GetOne<Admin.CYT369.Com.DAL.Domains.Apps.AppOperation>(c => c.Id == id);
        }

        public bool UpdateRoleMenu(List<Admin.CYT369.Com.DAL.Domains.Apps.RoleMenu> items)
        {
            bool update = false;

            using (var db = this.Ctx)
            {
                foreach (var item in items)
                {
                    var roleMenu = (from o in db.Set<Admin.CYT369.Com.DAL.Domains.Apps.RoleMenu>()
                                    where o.MenuID == item.MenuID && o.RoleID == item.RoleID
                                    select o).FirstOrDefault();

                    var operations = (from o in db.Set<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenuOperation>()
                                      where o.MenuID == item.MenuID && o.Enable
                                      select o).ToArray();

                    if (roleMenu == null)
                    {
                        foreach (var o in operations)
                        {
                            item.RoleMenuOperations.Add(new Admin.CYT369.Com.DAL.Domains.Apps.RoleMenuOperation()
                            {
                                OperationID = o.OperationID,
                                Enable = true
                            });
                        }

                        db.Set<Admin.CYT369.Com.DAL.Domains.Apps.RoleMenu>().Add(item);
                    }
                    else
                    {
                        roleMenu.Status = item.Status;
                        foreach (var op in operations)
                        {
                            var roleMenuOperation = (from o in db.Set<Admin.CYT369.Com.DAL.Domains.Apps.RoleMenuOperation>()
                                                     where o.OperationID == op.OperationID && o.RoleMenuID == roleMenu.Id
                                                     select o).FirstOrDefault();

                            if (roleMenuOperation == null)
                            {
                                if (item.Status > 0)
                                {
                                    item.RoleMenuOperations.Add(new Admin.CYT369.Com.DAL.Domains.Apps.RoleMenuOperation()
                                    {
                                        OperationID = op.OperationID,
                                        RoleMenuID = roleMenu.Id,
                                        Enable = true
                                    });
                                }
                            }
                            else
                            {
                                roleMenuOperation.Enable = (item.Status == 1 ? true : (item.Status == 2 ? true : false));
                                update = true;
                            }
                        }
                    }
                }

                return db.SaveChanges() > 0 || update;
            }
        }

        /// <summary>
        /// 更新操作权限配置信息
        /// </summary>
        /// <param name="roleId"></param>
        /// <param name="menuId"></param>
        /// <param name="operationId"></param>
        /// <param name="enable"></param>
        /// <returns></returns>
        public bool UpdateRoleMenuOperation(int roleId, int menuId, int operationId, bool enable)
        {
            bool update = false;
            using (var db = this.Ctx)
            {
                var roleMenu = (from o in db.Set<Admin.CYT369.Com.DAL.Domains.Apps.RoleMenu>()
                                where o.RoleID == roleId && o.MenuID == menuId
                                select o).FirstOrDefault();

                if (roleMenu != null)
                {
                    var op = (from o in db.Set<Admin.CYT369.Com.DAL.Domains.Apps.RoleMenuOperation>()
                              where o.RoleMenuID == roleMenu.Id && o.OperationID == operationId
                              select o).FirstOrDefault();

                    if (op != null)
                    {
                        op.Enable = enable;
                        update = true;
                    }
                    else
                    {
                        db.Set<Admin.CYT369.Com.DAL.Domains.Apps.RoleMenuOperation>().Add(new Admin.CYT369.Com.DAL.Domains.Apps.RoleMenuOperation()
                        {
                            RoleMenuID = roleMenu.Id,
                            OperationID = operationId,
                            Enable = enable
                        });
                    }
                }
                else
                {
                    roleMenu = new Admin.CYT369.Com.DAL.Domains.Apps.RoleMenu()
                    {
                        RoleID = roleId,
                        MenuID = menuId,
                    };
                    roleMenu.RoleMenuOperations.Add(new Admin.CYT369.Com.DAL.Domains.Apps.RoleMenuOperation()
                    {
                        RoleMenuID = roleMenu.Id,
                        OperationID = operationId,
                        Enable = enable
                    });

                    db.Set<Admin.CYT369.Com.DAL.Domains.Apps.RoleMenu>().Add(roleMenu);
                }

                return db.SaveChanges() > 0 || update;
            }
        }
        #endregion
    }
}
